﻿#pragma once
#include "DataBuffer.h"

_NAMESPACE_BEGIN

class BECode
{
public:
	BECode();
	enum OPEN_TYPE
	{
		OPEN_TYPE_READONLY,
		OPEN_TYPE_READWRITE,
		OPEN_TYPE_NEW
	};
	void AddRef();
	void Release();
	int refCount;///<引用计数

	bool Open(CONST_REF(wstring)filename,OPEN_TYPE type=OPEN_TYPE_READONLY);///<打开文件，如果是只读打开则不会载入节点信息，如果非只读，则一次性载入所有节点，这样保存的时候才不会丢失节点
	void Save(CONST_REF(wstring)filename=L"");
	void Close();
	void SetFileName(const TCHAR* filename){this->filename=filename;}
	const tstring& GetFileName(){return filename;}
	//读取配置文件然后关闭，里面记录了自定义的结构体类型，要在载入其他文件前执行
	void ReadConfigFile(const TCHAR* filename=NULL);
	void ClearAll();

#define BECODE_TYPE2ENUM(T) NODE_TYPE_##T

	enum NODE_TYPE
	{
		//0字节
		NODE_TYPE_EMPTY,//没有值
		//n字节
		BECODE_TYPE2ENUM(Buffer),//二进制缓冲
		BECODE_TYPE2ENUM(string),//多字符集字符串,以\0结尾
		BECODE_TYPE2ENUM(wstring),//UNICODE字符串,以\0结尾
		//1字节
		BECODE_TYPE2ENUM(bool),			BECODE_TYPE2ENUM(char),		BECODE_TYPE2ENUM(UCHAR),
		//二字节
		BECODE_TYPE2ENUM(short),		BECODE_TYPE2ENUM(USHORT),	
		//4字节
		BECODE_TYPE2ENUM(INT32),		BECODE_TYPE2ENUM(UINT32),		BECODE_TYPE2ENUM(float),
		//8字节
		BECODE_TYPE2ENUM(INT64),		BECODE_TYPE2ENUM(UINT64),		BECODE_TYPE2ENUM(double),

		NODE_TYPE_STRUCT,	//记录在配置文件中的结构体类型
		NODE_TYPE_USERSTRUCT,//在文件头定义的结构体类型
		NODE_TYPE_ARRAY//数组类型

	};
	NODE_TYPE GetType(){return pFocus->type;}

	void Write(Buffer& obj);	
	template<typename T>
	void Write(CONST_REF(T) obj)
	{
		//assert(NODE_TYPE_EMPTY==pFocus->type);
		WriteData(obj);			
	}		

	void Write(const char* obj)
	{
		//assert(NODE_TYPE_EMPTY==pFocus->type);
		string str=obj;
		Write(str);
	}	
	void Write(const TCHAR* obj)
	{
		//assert(NODE_TYPE_EMPTY==pFocus->type);
		wstring str=obj;
		Write(str);
	}	
#define BECODE_CHOOSE_TYPE(T) else if(typeid(T)==type) pFocus->type=BECODE_TYPE2ENUM(T);
	void Write(CONST_REF(boost::any) obj)
	{
		const type_info& type=obj.type();
		if(!type.name())
		{
			pFocus->type=NODE_TYPE_EMPTY;
		}
		BECODE_CHOOSE_TYPE(Buffer)
			BECODE_CHOOSE_TYPE(string)
			BECODE_CHOOSE_TYPE(wstring)
			BECODE_CHOOSE_TYPE(bool)		BECODE_CHOOSE_TYPE(char)		BECODE_CHOOSE_TYPE(UCHAR)
			BECODE_CHOOSE_TYPE(short)		BECODE_CHOOSE_TYPE(USHORT)
			BECODE_CHOOSE_TYPE(INT32)		BECODE_CHOOSE_TYPE(UINT32)		BECODE_CHOOSE_TYPE(float)
			BECODE_CHOOSE_TYPE(INT64)		BECODE_CHOOSE_TYPE(UINT64)		BECODE_CHOOSE_TYPE(double)

			pFocus->ct=obj;
	}

	void Write(__byte* p,DWORD len)
	{
		if(pFocus->ct.type()==typeid(Buffer))
		{
			Buffer* pb=boost::any_cast<Buffer>(&pFocus->ct);
			pb->Clear();
		}
		pFocus->type=BECODE_TYPE2ENUM(Buffer);
		Buffer buffer;
		pFocus->ct=boost::any(buffer);
		Buffer* pb=boost::any_cast<Buffer>(&pFocus->ct);
		pb->SetSize(len);
		memcpy(pb->GetBuffer(),p,len);
	}
	void WriteToEmpty()
	{
		pFocus->ct=boost::any();
		pFocus->type=NODE_TYPE_EMPTY;
	}

	//写入一个结构体,要考虑到结构体嵌套时，结构体对齐的问题！！！应该自动根据成员类型计算对齐的问题
	//对于没有string等指针类成员的可以直接copy sizeof的数据,有的需要手工处理
	template<typename T>
	void Write(const char* structname,T& obj)
	{
		hash_map<string,USHORT> f=structName2Index->find(structname);
		assert(structName2Index.end()!=f);
		pFocus->structTypeId=f.second;
		Buffer buffer;//由于从文件中读取时数据是未知类别的，所以统一用buffer保存
		pFocus->ct=boost::any(buffer);
		buffer.SetSize(sizeof(obj));
		memcpy(buffer.GetBuffer(),&obj,sizeof(obj));
		pFocus->type=NODE_TYPE_STRUCT;
	}

	void Read(boost::any& obj)
	{
		obj=pFocus->ct;
	}
	template<typename T>
	void Read(T& obj)
	{
		obj=*boost::any_cast<T>(&pFocus->ct);

	}
	void Read(Buffer*& obj);
	void Read(__byte* p,UINT& len);

	//读一个结构体
	template<typename T>
	void Read(const char* structname,T& obj)
	{
		hash_map<string,USHORT> f=structName2Index->find(structname);
		assert(structName2Index.end()!=f);
		assert(f.second==pFocus->structTypeId);
		Buffer buffer=*any_cast<Buffer>(&pFocus->ct);
		assert(sizeof(obj)==buffer.GetSize());
		memcpy(&obj,buffer.GetBuffer(),sizeof(obj));
	}

	//查找一个节点，可以用xml的路径语法/root/a/b
	bool FindNode(CONST_REF(string) npath,bool report=true);
	//将文件指针移动到一个节点,readcontent表示是否载入其内容
	bool GetSon(CONST_REF(string) name);
	bool GetSon(WORD index);
	bool GetLastSon();
	WORD GetSonNum();
	bool ToParent();
	const string& GetNodeName(){return pFocus->name;}		
	void SetNodeName(const char* name){this->pFocus->name=name;}

	///在当前节点下添加一个节点
	template<typename T>
	bool AddNode(CONST_REF(string) name,CONST_REF(T) obj)
	{
		pFocus=AddNode(name);
		Write(obj);
		pFocus=pFocus->pParent;
		return true;
	}
	bool AddNode(CONST_REF(string) name,Buffer& obj);
	bool AddNode(CONST_REF(string) name,__byte* p,DWORD len);
	template<typename T>
	bool AddNode(CONST_REF(string) name,const char* structname,T& obj)
	{
		pFocus=AddNode(name);
		Write(structname,obj);
		pFocus=pFocus->pParent;
		return true;
	}
	///删除当前节点
	bool DelNode(bool delsons=false);		

	class Node//一个节点 
	{
	public:
		Node();
		virtual ~Node();
		void AddSon(Node* p){p->pParent=this;sons.push_back(p);}
		void DelSon( Node* p );
		string name;///<节点名称，兄弟节点可重名
		NODE_TYPE type;///<节点类型
		boost::any ct;///<节点内容
		SHORT structTypeId;///<结构体类型的类型id，如果是结构体类型的话
		UINT bufferFilePos;//buffer在文件中的偏移，方便直接读取
		Node* pParent;
		std::vector<Node*> sons;
	};
	Node* GetFocusNodePtr(){return pFocus;}
	Node* GetRootNodePtr(){return pRoot;}
	void SetFocusNode(Node* p){this->pFocus=p;}

protected:
	//载入整个文件的节点结构.\param loadbuffer 是否载入二进制缓冲，以便更改后存回文件
	void ReadHierarchy(bool loadbuffer);
	void ReadNode(Node*& p,bool loadbuffer);

	void SaveNode(Node*p);
	///添加节点，如果父节点不存在会自动创建
	Node* AddNode(CONST_REF(string) npath);

	//\param 如果有子节点，是否继续删除

#define BECODE_WRITE_FUNCION(T) void WriteData(CONST_REF(T) obj){\
	pFocus->ct=boost::any(obj);			pFocus->type=BECODE_TYPE2ENUM(T);			}

	BECODE_WRITE_FUNCION(string)	BECODE_WRITE_FUNCION(wstring)
		BECODE_WRITE_FUNCION(bool)		BECODE_WRITE_FUNCION(char)		BECODE_WRITE_FUNCION(UCHAR)
		BECODE_WRITE_FUNCION(short)	BECODE_WRITE_FUNCION(USHORT)
		BECODE_WRITE_FUNCION(INT32)	BECODE_WRITE_FUNCION(UINT32)	BECODE_WRITE_FUNCION(float)
		BECODE_WRITE_FUNCION(INT64)	BECODE_WRITE_FUNCION(UINT64)	BECODE_WRITE_FUNCION(double)

#undef BECODE_WRITE_FUNCION

		tstring filename;
	DWORD fileSize;
	FILE* fp;
	Node* pRoot,*pFocus;
	OPEN_TYPE openType;
	WORD index;//当前指向的节点在父节点的编号

	Node* pStructTypeRoot;//下面的子节点记录自定义结构体类型
	hash_map<string,USHORT> structName2Index;///<记录自定义的结构体类型名称到structTypes中序号的映射
	std::vector<string> structIndex2Name;///<记录自定义的结构体类型名称到structTypes中序号的映射


private:
};
static BECode *BECodeDefaultFactory()
{
	return new BECode();
}

_NAMESPACE_END